<!--
 * @Author: HenryTSZ
 * @Date: 2020-03-21 10:13:51
 * @Description:
 * @LastEditors: HenryTSZ
 * @LastEditTime: 2020-05-16 11:53:24
-->
<template>
  <component :is="isForm ? 'el-form' : 'div'" v-bind="$attrs" :model="model" :ref="ref" class="base-form">
    <slot name="prev"></slot>
    <el-collapse v-if="collapse" v-model="activeNames" @change="handleChange">
      <el-collapse-item v-for="(group, index) in items" :name="`${index + 1}`">
        <template slot="title">
          <div style="display: flex; align-items: center;">
            <div style="background-color: #0455cb; width: 5px; height: 20px; margin-right: 5px;"></div>
            {{ group.label }}
          </div>
        </template>
        <el-row :gutter="20" justify="start">
          <el-col v-for="(item, index) in group.children" :key="index" :span="item.span ?? 12">
            <el-form-item :key="item.prop" :prop="item.prop" v-bind="item" :rules="[
              {
                required: item.required == undefined ? false : item.required,
                message: item.ruleMessage || `${handlePlaceholder(item.type)}${item.label}`,
                trigger: item.type === 'select' ? 'change' : 'blur'
              },
              ...(rules[item.prop] || [])
            ]">
              <!-- 用于自定义 label -->
              <slot v-bind:item="item" :name="`${item.prop}-label`"></slot>
              <!-- 具体组件的处理 -->
              <editable-elements :model="formModel" :item="item" v-on="$listeners">
                <template v-slot:[`${item.prop}-e`]="{ model, item }">
                  <slot :name="item.prop" v-bind="{ model, item }"></slot>
                </template>
              </editable-elements>
            </el-form-item>
          </el-col>
        </el-row>
      </el-collapse-item>
    </el-collapse>

    <el-row v-else :gutter="20" justify="start">
      <el-col v-for="(item, index) in items" :key="index" :span="item?.span ? item.span : 12">
        <el-form-item :key="item.prop" :prop="item.prop"  v-bind="item" :rules="[
          {
            required: item.required == undefined ? false : item.required,
            message: item.ruleMessage || `${handlePlaceholder(item.type)}${item.label}`,
            trigger: item.type === 'select' ? 'change' : 'blur'
          },
          ...(rules[item.prop] || [])
        ]">

          <!-- 用于自定义 label -->
          <slot v-bind:item="item" :name="`${item.prop}-label`"></slot>
          <!-- 具体组件的处理 -->
          <editable-elements :model="formModel" :item="item" v-on="$listeners">
            <template v-slot:[`${item.prop}-e`]="{ model, item }">
              <slot :name="item.prop" v-bind="{ model, item }"></slot>
            </template>
          </editable-elements>
        </el-form-item>
      </el-col>
    </el-row>

    <slot></slot>
  </component>
</template>

<script>

export default {
  name: 'BaseForm',
  components: { EditableElements: resolve => require(['./EditableElements'], resolve) },
  props: {
    keyProps: {
      type: Object,
      default() {
        return null
      }
    },
    model: {
      type: Object,
      default() {
        return {}
      }
    },
    formItems: {
      type: Array,
      default() {
        return []
      }
    },
    rules: {
      type: Object,
      default() {
        return {}
      }
    },
    collapse: {
      type: Boolean,
      default() {
        // 返回一个布尔值 true
        return false
      }
    },
    isForm: {
      type: Boolean,
      default() {
        return true
      }
    },
    ref:{
      type: String,
      default() {
        return ''
      }
    }
  },
  data() {
    return {
      formModel: {},
      activeNames: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
    }
  },
  computed: {
    items() {
      // 如果存在 keyProps
      return this.keyProps
        ? // 对 formItems 进行映射
        this.formItems.map(item => ({
          // 保留原 item 的所有属性
          ...item,
          // 将 prop 属性设置为 item[this.keyProps.prop] 或 item['prop']
          prop: item[this.keyProps.prop || 'prop'],
        }))
        : this.formItems
    }
  },
  watch: {
    formModel: {
      handler(val) {
        this.$emit('update:model', this.formModel)
      },
      deep: true
    }
  },
  methods: {
    handlePlaceholder(type) {
      if (['text', 'textarea', 'integer', 'decimal', 'input'].includes(type)) {
        return '请输入'
      } else if (
        ['select', 'radio', 'checkbox', 'date', 'cascader', 'switch', 'time', 'choose'].includes(type)
      ) {
        return '请选择'
      } else {
        return ''
      }
    },
    getFormData() {
      return this.formModel
    },
    deepSet(obj, path, value) {
      const keys = path.split('.');
      let current = obj;
      for (let i = 0; i < keys.length - 1; i++) {
        const key = keys[i];
        if (!current[key]) {
          this.$set(current, key, {});
        }
        current = current[key];
      }
      this.$set(current, keys[keys.length - 1], value);
    },
  },
  created() {
    this.formModel = { ...this.model }
    // 初始化表单数据
    if (this.collapse) {
      // this.activeNames = this.formItems.map((_, index) => `${index + 1}`)
      this.items.forEach(group => {
        group.children.forEach(item => {
          const arr_key = item.prop.split('.');
          if (arr_key.length > 1) {
            this.deepSet(this.formModel, item.prop, this.model[item.prop] || '')  
          } else {
            this.$set(this.formModel, item.prop, this.model[item.prop] || '')
          }

        });
      });
    } else {
      this.items.forEach(item => {
        const arr_key = item.prop.split('.');
          if (arr_key.length > 1) {
            this.deepSet(this.formModel, item.prop, this.model[item.prop] || '')  
          } else {
            this.$set(this.formModel, item.prop, this.model[item.prop] || '')
          }
      });
    }
  },
  mounted() {
    for (let key in this.$refs.elForm) {
      if (!(key in this) && typeof this.$refs.elForm[key] === 'function') {
        this[key] = this.$refs.elForm[key].bind(this.$refs.elForm)
      }
    }
    
  }
}
</script>

<!-- <style lang="less" scope>
 .el-collapse-item__header{
    background-color: yellow;
  }
</style> -->
